package com.cold.legendary.mock.context.whole;

import com.cold.legendary.mock.context.whole.element.WholeMockInjectElement;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * mock元素上下文
 *
 * @author cold
 * @since  2021/12/24
 */
@Slf4j
public class WholeMockContext {

    private volatile static WholeMockContext wholeMockContext;

    /**
     * mock元素关联map
     */
    private static Map<String, WholeMockInjectElement> injectElementMap = new ConcurrentHashMap<>();

    public static WholeMockContext getInstance() {
        if (null == wholeMockContext) {
            synchronized (WholeMockContext.class) {
                if (null == wholeMockContext) {
                    wholeMockContext = new WholeMockContext();
                }
            }
        }
        return wholeMockContext;
    }

    /**
     * 注册全局mock注入关系
     * @param mockInjectBeanClazz mockInjectBeanClazz
     * @param mockInjectBeanObj mockInjectBeanObj
     * @param mockBeanClazzLs  mockBeanClazzLs
     */
    public void register(Class mockInjectBeanClazz, Object mockInjectBeanObj, List<Class> mockBeanClazzLs) {
        if(null == injectElementMap) {
            injectElementMap = new ConcurrentHashMap<>();
        }
        String mockInjectBeanName = mockInjectBeanClazz.getName();
        WholeMockInjectElement injectElement = injectElementMap.get(mockInjectBeanName);
        if (null == injectElement) {
            WholeMockInjectElement element = new WholeMockInjectElement();
            element.setMockBeanClazzes(mockBeanClazzLs);
            element.setMockInjectBeanObj(mockInjectBeanObj);

            injectElementMap.put(mockInjectBeanName, element);
        } else {
            List<Class> mapMockBeanClazzes = injectElement.getMockBeanClazzes();

            mapMockBeanClazzes = new ArrayList<>(mapMockBeanClazzes);

            mapMockBeanClazzes.removeIf(e -> mockBeanClazzLs.stream().anyMatch(m -> m.getName().equals(e.getName())));
            mapMockBeanClazzes.addAll(mockBeanClazzLs);

            injectElement.setMockInjectBeanObj(mockInjectBeanObj);
            injectElement.setMockBeanClazzes(mapMockBeanClazzes);
            injectElementMap.put(mockInjectBeanName, injectElement);
        }

        //动态代理注入
        injectElementMap.forEach((injectBeanName, element) -> {
            try {
                element.inject();
            } catch (Exception e) {
                log.error("动态代理注入失败!", e);
            }
        });

    }

    public void cleanWholeMockContext() {
        if(null != injectElementMap) {
            injectElementMap.clear();
        }
    }
}
